package com.movitech.wechat;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.gson.bean.Articles;
import com.gson.bean.Attachment;
import com.gson.bean.InMessage;
import com.gson.bean.OutMessage;
import com.gson.inf.MessageProcessingHandler;
import com.gson.oauth.Group;
import com.gson.oauth.Menu;
import com.gson.oauth.Message;
import com.gson.oauth.Qrcod;
import com.gson.oauth.User;
import com.gson.util.ConfKit;
import com.gson.util.HttpKit;
import com.gson.util.Tools;
import com.gson.util.XStreamFactory;
import com.thoughtworks.xstream.XStream;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.log4j.Logger;

public class WeChat
{
  private static final String ACCESSTOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
  private static final String PAYFEEDBACK_URL = "https://api.weixin.qq.com/payfeedback/update";
  private static final String DEFAULT_HANDLER = "com.movitech.wechat.WeChatMessageProcessingHandlerImpl";
  private static final String GET_MEDIA_URL = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=";
  private static final String UPLOAD_MEDIA_URL = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=";
  private static final Logger LOGGER = Logger.getLogger(WeChat.class);

  private static Class<?> messageProcessingHandlerClazz = null;

  public static final Message message = new Message();

  public static final Menu menu = new Menu();

  public static final User user = new User();

  public static final Group group = new Group();

  public static final Qrcod qrcod = new Qrcod();

  public static String getAccessToken()
    throws Exception
  {
    String appid = ConfKit.get("AppId");
    String secret = ConfKit.get("AppSecret");
    String jsonStr = HttpKit.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential".concat("&appid=") + appid + "&secret=" + secret);
    Map map = JSONObject.parseObject(jsonStr);
    return map.get("access_token").toString();
  }

  public static boolean payfeedback(String openid, String feedbackid)
    throws Exception
  {
    Map map = new HashMap();
    String accessToken = getAccessToken();
    map.put("access_token", accessToken);
    map.put("openid", openid);
    map.put("feedbackid", feedbackid);
    String jsonStr = HttpKit.get("https://api.weixin.qq.com/payfeedback/update", map);
    Map jsonMap = JSONObject.parseObject(jsonStr);
    return "0".equals(jsonMap.get("errcode").toString());
  }

  public static Boolean checkSignature(String token, String signature, String timestamp, String nonce)
  {
    return Boolean.valueOf(Tools.checkSignature(token, signature, timestamp, nonce));
  }

  public static String processing(String responseInputString)
  {
    InMessage inMessage = parsingInMessage(responseInputString);
    LOGGER.debug("输入消息:[" + inMessage.getContent() + "]");
    OutMessage oms = null;

    if (messageProcessingHandlerClazz == null)
    {
      String handler = ConfKit.get("MessageProcessingHandlerImpl");
      handler = (handler == null) ? "com.movitech.wechat.WeChatMessageProcessingHandlerImpl" : handler;
      try {
        messageProcessingHandlerClazz = Thread.currentThread().getContextClassLoader().loadClass(handler);
      } catch (Exception e) {
        throw new RuntimeException("messageProcessingHandler Load Error！");
      }
    }
    String xml = "";
    try {
      MessageProcessingHandler messageProcessingHandler = (MessageProcessingHandler)messageProcessingHandlerClazz.newInstance();

      String type = inMessage.getMsgType();
      String qrcode = null;

      Method getOutMessage = messageProcessingHandler.getClass().getMethod("getOutMessage", new Class[0]);

      Method mt = messageProcessingHandler.getClass().getMethod(type + "TypeMsg", new Class[] { InMessage.class });

      if (mt != null) {
        mt.invoke(messageProcessingHandler, new Object[] { inMessage });
      }

      Object obj = getOutMessage.invoke(messageProcessingHandler, new Object[0]);
      if (obj != null) {
        oms = (OutMessage)obj;
      }
      try
      {
        Method aftMt = messageProcessingHandler.getClass().getMethod("afterProcess", new Class[] { InMessage.class, OutMessage.class });
        aftMt.invoke(messageProcessingHandler, new Object[] { inMessage, oms });
      } catch (Exception localException1) {
      }
      obj = getOutMessage.invoke(messageProcessingHandler, new Object[0]);
      if (obj != null) {
        oms = (OutMessage)obj;
        setMsgInfo(oms, inMessage);
      }
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    if (oms != null)
    {
      XStream xs = XStreamFactory.init(true);
      xs.alias("xml", oms.getClass());
      xs.alias("item", Articles.class);
      xml = xs.toXML(oms);
      LOGGER.debug("output message:" + xml);
    }
    return xml;
  }

  private static void setMsgInfo(OutMessage oms, InMessage msg)
    throws Exception
  {
    if (oms != null) {
      Class outMsg = oms.getClass().getSuperclass();
      Field CreateTime = outMsg.getDeclaredField("CreateTime");
      Field ToUserName = outMsg.getDeclaredField("ToUserName");
      Field FromUserName = outMsg.getDeclaredField("FromUserName");

      ToUserName.setAccessible(true);
      CreateTime.setAccessible(true);
      FromUserName.setAccessible(true);

      CreateTime.set(oms, Long.valueOf(new Date().getTime()));
      ToUserName.set(oms, msg.getFromUserName());
      FromUserName.set(oms, msg.getToUserName());
    }
  }

  private static InMessage parsingInMessage(String responseInputString)
  {
    XStream xs = XStreamFactory.init(false);
    xs.ignoreUnknownElements();
    xs.alias("xml", InMessage.class);
    InMessage msg = (InMessage)xs.fromXML(responseInputString);
    return msg;
  }

  public static Attachment getMedia(String accessToken, String mediaId)
    throws IOException
  {
    String url = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=" + accessToken + "&media_id=" + mediaId;
    return HttpKit.download(url);
  }

  public static Map<String, Object> uploadMedia(String accessToken, String type, File file)
    throws KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException, IOException
  {
    String url = "http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=" + accessToken + "&type=" + type;
    String jsonStr = HttpKit.upload(url, file);
    return (Map)JSON.parseObject(jsonStr, Map.class);
  }

  public static boolean isWeiXin(HttpServletRequest request)
  {
    String userAgent = request.getHeader("User-Agent");
    if (StringUtils.isNotBlank(userAgent)) {
      Pattern p = Pattern.compile("MicroMessenger/(\\d+).+");
      Matcher m = p.matcher(userAgent);
      String version = null;
      if (m.find()) {
        version = m.group(1);
      }
      return (version != null) && (NumberUtils.toInt(version) >= 5);
    }
    return false;
  }
}